package com.framework.boc.admin.security.filters;

import com.framework.boc.admin.security.service.MyUserDetailsService;
import com.framework.boc.admin.security.sms.SmsCodeAuthenticationToken;
import com.framework.boc.admin.security.sms.exception.SmsCodeException;
import com.framework.boc.admin.security.utils.JwtUtil;
import com.framework.boc.admin.security.utils.ResponseUtil;
import com.framework.boc.admin.sms.SmsCode;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

public class JwtRequestFilter extends OncePerRequestFilter {

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    ResponseUtil responseUtil;

    @Autowired
    AntPathMatcher antPathMatcher;

    private List<String> patterns;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        if (requestMatchersPermit(request.getRequestURI())) {
            filterChain.doFilter(request, response);
            return;
        }

        final String authorizationHeader = request.getHeader("Authorization");

        if (StringUtils.isNotEmpty(authorizationHeader) && authorizationHeader.startsWith("Bearer ")) {
            String jwt = authorizationHeader.substring(7);
            try {
                validateToken(request, jwt);
            } catch (Exception e) {
                logger.error(e.getMessage());
                Map<String, Object> res = new HashMap<>();
                res.put("code", HttpServletResponse.SC_UNAUTHORIZED);
                res.put("msg", e.getMessage());
                responseUtil.WriteInfoToResponse(response, res, HttpServletResponse.SC_UNAUTHORIZED);
                return;
            }
        }

        filterChain.doFilter(request, response);
    }



    // 验证jwt token
    private void validateToken(HttpServletRequest request, String jwt) throws Exception {
        try {
            String subject = jwtUtil.extractUsername(jwt);
            if (StringUtils.isNotEmpty(subject) && SecurityContextHolder.getContext().getAuthentication() == null) {

                if (jwtUtil.validateToken(jwt, subject)) {
                    String authorities = jwtUtil.extractClaim(jwt, claims -> (String) claims.get("authorities"));
                    String[] authoritiesArr = StringUtils.split(authorities, ",");
                    List<SimpleGrantedAuthority> authorities1 = Arrays.stream(authoritiesArr).map(authority -> new SimpleGrantedAuthority(authority))
                            .collect(Collectors.toList());
                    SmsCodeAuthenticationToken token = new SmsCodeAuthenticationToken(subject, authorities1);
//                    token.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    SecurityContextHolder.getContext().setAuthentication(token);
                } else {
                    throw new Exception("无效的token");
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
            throw new Exception("token格式异常");
        }
    }


    public void antMatchersPermit(String... patterns) {
        this.patterns = Arrays.asList(patterns);
    }


    protected boolean requestMatchersPermit(String requestUrl) {
        boolean res = this.patterns.stream()
                .anyMatch(pattern -> antPathMatcher.match(pattern, requestUrl));
        return res;
    }

}
